package database

import (
	"fmt"
	"go_web/internal/global"
	"go_web/pkg/config"
	"go_web/pkg/utils"
	"log"
	"reflect"
	"sync"
	"time"

	"github.com/bwmarrin/snowflake"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var (
	once sync.Once // 确保连接只初始化一次
)

func Init() error {
	var err error
	once.Do(func() {
		// 读配置
		cfg := config.Get()

		// 构建 MySQL DSN
		dsn := fmt.Sprintf(
			"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=%s",
			cfg.Database.User,      // 数据库用户名（config.yaml 中的 database.user）
			cfg.Database.Password,  // 数据库密码（config.yaml 中的 database.password）
			cfg.Database.Host,      // 数据库地址（config.yaml 中的 database.host）
			cfg.Database.Port,      // 数据库端口（config.yaml 中的 database.port）
			cfg.Database.DBName,    // 数据库名（config.yaml 中的 database.db_name）
			cfg.Database.Charset,   // 字符集（config.yaml 中的 database.charset）
			cfg.Database.ParseTime, // 是否解析时间（config.yaml 中的 database.parse_time）
			cfg.Database.Loc,       // 时区（config.yaml 中的 database.loc）
		)

		global.DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
			Logger: logger.Default.LogMode(logger.Info), // 日志级别（可选：Silent/Error/Warn/Info）
		})
		if err != nil {
			err = fmt.Errorf("数据库连接失败: %w", err)
			return
		}

		// 配置连接池（避免数据库连接泄露）
		sqlDB, _ := global.DB.DB()
		sqlDB.SetMaxOpenConns(100)                 // 最大打开连接数
		sqlDB.SetMaxIdleConns(20)                  // 最大空闲连接数
		sqlDB.SetConnMaxLifetime(30 * time.Minute) // 连接最大存活时间
		sqlDB.SetConnMaxIdleTime(10 * time.Minute) // 连接最大空闲时间

		global.IdWorker, err = snowflake.NewNode(1)

		// 全局新增钩子
		global.DB.Callback().Create().Before("gorm:create").Register("before_create_hook", func(tx *gorm.DB) {
			if err != nil {
				tx.AddError(fmt.Errorf("snowflake node creation failed: %v", err))
				return
			}

			// 判断 gin.Context 是否有效，并处理批量插入
			if ginCtx, ok := tx.Statement.Context.(*gin.Context); ok {
				token, err := utils.GetTokenFromHeader(ginCtx)
				var userId int64
				if err == nil {
					userId, err = utils.GetUserIdFromToken(*token)
					if err != nil {
						fmt.Println("get user id failed: %v", err)
					}
				} else {
					fmt.Println("get user id failed: %v", err)
				}

				if tx.Statement.Schema != nil && tx.Statement.ReflectValue.IsValid() {
					value := tx.Statement.ReflectValue
					if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
						for i := 0; i < value.Len(); i++ {
							elem := value.Index(i)
							elemValue := elem.Elem()
							if elemValue.FieldByName("ID").IsZero() {
								elemValue.FieldByName("ID").SetInt(global.IdWorker.Generate().Int64())
							}
							if elemValue.FieldByName("CreateTime").IsZero() {
								elemValue.FieldByName("CreateTime").Set(reflect.ValueOf(time.Now()))
							}
							if elemValue.FieldByName("CreatorId").IsZero() {
								elemValue.FieldByName("CreatorId").SetInt(userId)
							}
							elemValue.FieldByName("ModifyTime").Set(reflect.ValueOf(time.Now()))
							elemValue.FieldByName("ModifierId").SetInt(userId)
						}
					} else {
						if value.FieldByName("ID").IsZero() {
							value.FieldByName("ID").SetInt(global.IdWorker.Generate().Int64())
						}
						if value.FieldByName("CreateTime").IsZero() {
							value.FieldByName("CreateTime").Set(reflect.ValueOf(time.Now()))
						}
						if value.FieldByName("CreatorId").IsZero() {
							value.FieldByName("CreatorId").SetInt(userId)
						}
						value.FieldByName("ModifyTime").Set(reflect.ValueOf(time.Now()))
						value.FieldByName("ModifierId").SetInt(userId)
					}
				}
				//tx.Statement.SetColumn("id", global.IdWorker.Generate().Int64())
				//tx.Statement.SetColumn("create_time", time.Now())

				//tx.Statement.SetColumn("creator_id", userId)

			}
		})

		// 全局修改钩子
		global.DB.Callback().Update().Before("gorm:update").Register("before_update_hook", func(tx *gorm.DB) {
			// 判断 gin.Context 是否有效，并处理批量插入
			if ginCtx, ok := tx.Statement.Context.(*gin.Context); ok {
				token, err := utils.GetTokenFromHeader(ginCtx)
				if err != nil {
					return
				}
				userId, err := utils.GetUserIdFromToken(*token)
				if err != nil {
					log.Fatalln(fmt.Errorf("get user id failed: %v", err))
					return // 啥都不做
				}
				tx.Statement.SetColumn("modify_time", time.Now())

				tx.Statement.SetColumn("modifier_id", userId)
			}
		})

	})
	return err
}

func Close() error {
	sqlDB, err := global.DB.DB()
	if err != nil {
		return err
	}
	return sqlDB.Close()
}
